#ifndef YHAIDA_RPCCHANNEL_H
#define YHAIDA_RPCCHANNEL_H

#include "../../server/logging/Logging.h"
#include "../../server/thread/Atomic.h"
#include "../../server/mutex/MutexLock.h"
#include "../../server/net/Buffer.h"
#include "../../server/net/TcpConnection.h"
#include "../proto/rpc.pb.h"

#include "RpcCodec.h"
#include <map>
#include <string>
// Service and RpcChannel classes are incorporated from
#include <google/protobuf/service.h>
namespace google
{
    namespace protobuf
    {

        //前向声明->方便后续调用
        class Descriptor;        // descriptor.h
        class ServiceDescriptor; // descriptor.h
        class MethodDescriptor;  // descriptor.h
        class Message;           // message.h

        class Closure;

        class RpcController;
        class Service;

    }
}
namespace yhaida
{
    namespace rpc
    {
        class RpcChannel : public google::protobuf::RpcChannel
        {
        public:
            RpcChannel();
            explicit RpcChannel(const TcpConnectionPtr &conn);

            ~RpcChannel() override;

            void setConnection(const TcpConnectionPtr &conn)
            {
                _conn = conn;
            }
                             
            void setServices(const std::map<std::string, ::google::protobuf::Service *>* services)
            {
                _services = services;
            }

            void onMessage(const TcpConnectionPtr &conn,
                           Buffer *buffer,
                           Timestamp receivTime);

        public:
        //   virtual void CallMethod(const MethodDescriptor* method,
        //                   RpcController* controller, const Message* request,
        //                   Message* response, Closure* done) = 0;
            void CallMethod(const ::google::protobuf::MethodDescriptor *method,
                            ::google::protobuf::RpcController *controller,
                            const ::google::protobuf::Message *request,
                            ::google::protobuf::Message *response,
                            ::google::protobuf::Closure *done) override;

        private:
            /**
             * @brief  注册->回调函数到_codec中->具体的消息类型中去
             */
            void onRpcMessage(const TcpConnectionPtr &conn,
                              const RpcMessagePtr &messagePtr,
                              Timestamp receiveTime);
            void doneCallback(::google::protobuf::Message *response, int64_t id);

            struct OutstandingCall
            {
                ::google::protobuf::Message *response;
                ::google::protobuf::Closure *done;
            };

        private:
            RpcCodec _codec;

            TcpConnectionPtr _conn;
            
            AtomicInt64 _id;
            MutexLock _mutex;

            std::map<int64_t, OutstandingCall> _outstandings;

            //由服务器set
            const std::map<std::string, ::google::protobuf::Service *> *_services;
        };

        typedef std::shared_ptr<RpcChannel> RpcChannelPtr;

    }
}

#endif